{*******************************************************************************
* The contents of this file are used with permission, subject to the Mozilla   *
* Public License Version 1.1 (the "License"); you may not use this file except *
* in compliance with the License. You may obtain a copy of the License at      *
* http://www.mozilla.org/MPL/                                                  *
*                                                                              *
* Software distributed under the License is distributed on an "AS IS" basis,   *
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for *
* the specific language governing rights and limitations under the License.    *
*                                                                              *
* The Original Code is distributed as part of the "mediate" product and is     *
* Copyright (C) @home media limited. All Rights Reserved.                      *
*                                                                              *
* Email: support@athomemedia.co.uk                                             *
* Web:   http://www.athomemedia.co.uk                                          *
*******************************************************************************}

unit Timers;

interface

uses Classes, UIObjects, Actions, XMLHelper;

{$IFDEF DESIGNER}
const
  MODIFY_CAPTION = 'Edit Actions';

  // Property categories and hints for designer
  CAT_TIMER = 'Timer';
  HINT_ACTIONS = 'defines action handling for this timer';
  HINT_INTERVAL = 'specifies the timer delay interval in milliseconds';
  HINT_REPEAT = 'determines whether the timer will fire repeatedly or just once';
  HINT_ENABLED = 'controls whether or not the timer is enabled';
{$ENDIF}

type
  TAHMTimer = class(TAHMUIObject)
  private
    FInterval: Integer;
    FRepeat: Boolean;
    FEnabled: Boolean;
    FActions: TAHMActionList;
  protected
    procedure ClearProperties; override;
  public
    constructor Create(const Name: String); override;
    destructor Destroy; override;
    function RenderPreview: Boolean; override;
    function ModifyActions: Integer; override;
    function Modify(Action: Integer): Boolean; override;
    function ModifyCaption(Action: Integer): String; override;
    procedure SeedObject; override;
    procedure Assign(Source: TPersistent); override;
    procedure AssignContents(Source: TAHMUIObject); override;
    procedure SaveXMLBody(Lines: TStrings); override;
    procedure ParseFromXML(XML: TAHMXMLHelper); override;
    procedure BuildProperties(Properties: TAHMUIPropertyList); override;
  published
    property Actions: TAHMActionList read FActions;
    property Interval: Integer read FInterval write FInterval;
    property RepeatTimer: Boolean read FRepeat write FRepeat;
    property Enabled: Boolean read FEnabled write FEnabled;
  end;

  TAHMTimerList = class(TAHMUIObjectList)
  private
  protected
  public
    constructor Create; override;
    function AddTimer(const InheritFrom, NewName: String): TAHMTimer; overload;
    function GetTimer(const Name: String): TAHMTimer;
    procedure InitialiseTimers;
  end;


implementation

uses SysUtils, TagNames, XMLTags, ApplicationManager, Screen, Functions,
     {$IFDEF DESIGNER}DesignerList,{$ENDIF} AHMTypes;

constructor TAHMTimerList.Create;
begin
  inherited Create;

  XMLTagName := TAG_TIMERS;
  ChildClass := TAHMTimer;
end;

function TAHMTimerList.AddTimer(const InheritFrom, NewName: String): TAHMTimer;
begin
  Result := TAHMTimer(Inherit(InheritFrom, NewName));
end;

function TAHMTimerList.GetTimer(const Name: String): TAHMTimer;
begin
  Result := TAHMTimer(GetObject(Name));
end;

procedure TAHMTimerList.InitialiseTimers;
var
  i: Integer;
  Timer: TAHMTimer;
begin
  // Auto start all enabled timers
  for i := 0 to Pred(Count) do
  begin
    Timer := TAHMTimer(Objects[i]);
    if Timer.Enabled then
      ApplicationManagerInstance.TimerManager.StartTimer(Timer);
  end;
end;

//----------------------------------------------------------------------------//

constructor TAHMTimer.Create(const Name: String);
begin
  inherited Create(Name);

  XMLTagName := TAG_TIMER;
  ObjectType := otTimers;
  ImageIndex := Ord(otTimers);

  FActions := TAHMActionList.Create;
  FActions.Owner := Self;
end;

destructor TAHMTimer.Destroy;
begin
  FActions.FreeWithContents;

  inherited;
end;

procedure TAHMTimer.ClearProperties;
begin
  inherited;

  // Clear custom timer properties
  FInterval := 0;
  FRepeat := False;
  FEnabled := False;
  FActions.ClearObjects;
end;

function TAHMTimer.RenderPreview: Boolean;
begin
{$IFDEF DESIGNER}
  with ScreenInstance.Viewport do
  begin
    Canvas.DesignerBackground(ViewportRect);
    Canvas.TextRect(ViewportRect, nil, 'Timer Properties' + sLineBreak +
                    sLineBreak + 'Interval: ' + IntToStr(FInterval) +
                    sLineBreak + 'Repeating: ' + Bool2Str(FRepeat) +
                    sLineBreak + 'Enabled: ' + Bool2Str(FEnabled) +
                    sLineBreak + sLineBreak + 'Actions:' + sLineBreak +
                    FActions.Text);
  end;
{$ENDIF}
  Result := True;
end;

function TAHMTimer.ModifyActions: Integer;
begin
  // Timer only supports editing actions
  Result := 1;
end;

function TAHMTimer.Modify(Action: Integer): Boolean;
begin
{$IFDEF DESIGNER}
  // Edit actions with list dialog
  Result := TfrmObjectList.ShowList(FActions, nil, nil);

  if Result then DoModified;
{$ELSE}
  Result := False;
{$ENDIF}
end;

function TAHMTimer.ModifyCaption(Action: Integer): String;
begin
{$IFDEF DESIGNER}
  Result := MODIFY_CAPTION;
{$ELSE}
  Result := '';
{$ENDIF}
end;

procedure TAHMTimer.SeedObject;
begin
{$IFDEF DESIGNER}
  if Ancestor = nil then
  begin
    Interval := 1000;
    RepeatTimer := True;
    Enabled := True;
    Actions.AddAction('', AC_ONTIMERSTART).ActionFunction := FN_NONE;
    Actions.AddAction('', AC_ONTIMER).ActionFunction := FN_NONE;
    Actions.AddAction('', AC_ONTIMERSTOP).ActionFunction := FN_NONE;
  end;
{$ENDIF}
end;

procedure TAHMTimer.Assign(Source: TPersistent);
begin
  inherited Assign(Source);

  with Source as TAHMTimer do
  begin
    Self.Interval := Interval;
    Self.RepeatTimer := RepeatTimer;
    Self.Enabled := Enabled;
    Self.Actions.ClearObjects;
    Self.Actions.BaseList := Actions;
  end;
end;

procedure TAHMTimer.AssignContents(Source: TAHMUIObject);
begin
  inherited;

  with Source as TAHMTimer do
    Self.Actions.AssignContents(Actions);
end;

procedure TAHMTimer.SaveXMLBody(Lines: TStrings);
var
  oAncs: TAHMTimer;
  sWork: String;
begin
  // Determine which ancestor to compare against - real or empty
  oAncs := TAHMTimer(ObjectToCompare);

  // Only populate attributes that differ from our ancestor
  if (FInterval <> 0) and (FInterval <> oAncs.Interval) then
    Lines.Add(TABS[3] + TGB+TAG_INTERVAL+TGC + IntToStr(FInterval) + TGE+TAG_INTERVAL+TGC);

  // Do we need to store characteristics?
  if (FRepeat and (FRepeat <> oAncs.RepeatTimer)) or
     (FEnabled and (FEnabled <> oAncs.Enabled)) then
  begin
    sWork := TGB+TAG_PROPERTIES;
     if FRepeat and (FRepeat <> oAncs.RepeatTimer) then
       sWork := sWork + SPC+ATTR_REPEAT+ATB + Bool2Str(FRepeat) + ATQ;
     if FEnabled and (FEnabled <> oAncs.Enabled) then
       sWork := sWork + SPC+ATTR_ENABLED+ATB + Bool2Str(FEnabled) + ATQ;
     Lines.Add(TABS[3] + sWork + ETE);
  end;

  // Do we need to store actions?
  if FActions.IsDifferent(oAncs.Actions) then
  begin
    FActions.XMLIndent := 2;
    FActions.XMLTagName := TAG_ACTIONS;
    FActions.SaveDiffsAsXML(oAncs.Actions, Lines);
  end;
end;

procedure TAHMTimer.ParseFromXML(XML: TAHMXMLHelper);
var
  sRepeat, sEnabled: String;
  TimerNode, PropsNode: TAHMXMLNode;
begin
  // Initialise parsing nodes
  TimerNode := XML.CurrentNode;
  PropsNode := nil;

  // Discover additional properties for this object
  while XML.NextElement(TimerNode, PropsNode) do
    if XML.CurrentElement = TAG_INTERVAL then
    begin
      FInterval := StrToIntDef(XML.GetValue, 0);
    end
    else if XML.CurrentElement = TAG_PROPERTIES then
    begin
      sRepeat := XML.GetAttribute(ATTR_REPEAT);
      sEnabled := XML.GetAttribute(ATTR_ENABLED);
      if sRepeat <> '' then FRepeat := Str2Bool(sRepeat);
      if sEnabled <> '' then FEnabled := Str2Bool(sEnabled);
    end
    else if XML.CurrentElement = TAG_ACTIONS then
    begin
      FActions.ParseFromXML(XML);
    end;
end;

procedure TAHMTimer.BuildProperties(Properties: TAHMUIPropertyList);
begin
{$IFDEF DESIGNER}
  inherited;

  // Build custom timer properties
  Properties.Add('Actions', 'Actions', CAT_TIMER, HINT_ACTIONS);
  Properties.Add('Interval', 'Interval', CAT_TIMER, HINT_INTERVAL);
  Properties.Add('Repeating', 'RepeatTimer', CAT_TIMER, HINT_REPEAT);
  Properties.Add('Enabled', 'Enabled', CAT_TIMER, HINT_ENABLED);
{$ENDIF}
end;

end.
